
#include <iostream>
using namespace std;

#include <pthread.h>
#include <unistd.h>
#include <ctime>

#include <string>

// // 线程数据，包含线程名字，也就是黄牛名字，还有线程对应的互斥锁
// class ThreadData
// {
// public:
//     ThreadData(const string& name, pthread_mutex_t* pmtx, pthread_cond_t* pcond)
//         :_name(name),
//          _pmtx(pmtx),
//          _pcond(pcond)
//     {}

// public:
//     string _name;
//     pthread_mutex_t* _pmtx;
//     pthread_cond_t* _pcond;
// };

// // 黄牛人数
// #define THREAD_NUM 5

// bool quit = false;

// // 陈奕迅演唱会的票数tickets
// int tickets = 100;

// // 黄牛抢票执行的方法
// void* getTicket(void* arg)
// {
//     ThreadData* ptd = (ThreadData*)arg;
    
//     while(!quit)
//     {
//         // 访问临界资源前先加锁
//         pthread_mutex_lock(ptd->_pmtx);
//         // 进入cond的等待队列中，相当于if(tickets > 0)
//         pthread_cond_wait(ptd->_pcond, ptd->_pmtx);
        
//         //访问临界资源
//         tickets--;
//         printf("%s抢到票了, 票数为 ::%d\n", ptd->_name.c_str(), tickets);

//         // 解锁
//         pthread_mutex_unlock(ptd->_pmtx);
//     }
    
//     // cout << ptd->_name << "退出" << endl;
//     printf("%s退出", ptd->_name.c_str());
//     // 记得要释放掉线程数据，不然内存泄漏
//     delete ptd;

//     return nullptr;
// }

// int main()
// {
//     // 条件变量
//     pthread_cond_t cond;
//     pthread_cond_init(&cond, nullptr);

//     // 局部锁
//     pthread_mutex_t mtx;
//     // 默认初始化
//     pthread_mutex_init(&mtx, nullptr);

//     // 种一颗随机数种子
//     srand((unsigned int)time(nullptr) ^ getpid() ^ 0x24233342);
//     // 假设此时有THREAD_NUM个黄牛进行抢票
//     pthread_t tid[THREAD_NUM];

//     for(int i = 0; i < THREAD_NUM; ++i)
//     {
//         string tmp;
//         tmp += to_string(i + 1) + "号黄牛";
//         ThreadData* ptd = new ThreadData(tmp, &mtx, &cond);

//         // 每个黄牛去抢票
//         pthread_create(tid + i, nullptr, getTicket, (void*)ptd);
//     }

//     //sleep(2);
//     printf("开始售票\n");

//     while(tickets > 5)
//     {
//         // 一次一个
//         pthread_cond_signal(&cond);
//         usleep(2000);
//     }

//     quit = true;
//     pthread_cond_broadcast(&cond);

//     printf("main退出\n");

//     // 等待每个黄牛抢完票后退出
//     for(int i = 0; i < THREAD_NUM; ++i)
//     {
//         pthread_join(tid[i], nullptr);
//     }

//     pthread_mutex_destroy(&mtx);
//     return 0;
// }

#include <vector>


// 线程个数
const static int THREAD_NUM = 4;

// 不同线程的执行方法
/**********************************************************************************/
void Thread_1_Func(const string& name)
{
    cout << name << "is doing" << " 加密工作" << endl;
}

void Thread_2_Func(const string& name)
{
    cout << name << "is doing" << " 持久化工作" << endl;
}

void Thread_3_Func(const string& name)
{
    cout << name << "is doing" << " 查询工作" << endl;
}

void Thread_4_Func(const string& name)
{
    cout << name << "is doing" << " 管理工作" << endl;
}
/**********************************************************************************/

// 函数指针，指向线程所要执行的函数
typedef void(*pfunc)(const string& name);

// 每个线程最有用的数据
class ThreadData
{
public:
    ThreadData(const string& name, pthread_mutex_t* pmtx, pthread_cond_t* pcond, pfunc pf)
        :_name(name),
         _pmtx(pmtx),
         _pcond(pcond),
         _pf(pf)
    {}

public:
    string _name; // 线程名
    pthread_mutex_t* _pmtx; // 锁
    pthread_cond_t* _pcond; // 条件变量
    pfunc _pf; // 回调函数
};

// 判断线程是否退出
static bool quit = false;

// pthread_create的回调方法
void* ThreadRoutine(void* arg)
{
    ThreadData* ptd = (ThreadData*)arg;

    while(!quit)
    {
        // 访问临界资源前上锁
        pthread_mutex_lock(ptd->_pmtx);

        // 相当于if判断，此时线程直接阻塞
        pthread_cond_wait(ptd->_pcond, ptd->_pmtx);
        
        if(!quit)
        {
            // 去调用线程对应的方法
            ptd->_pf(ptd->_name);
        }
        else
        {
            // 退出
            cout << ptd->_name << " quit" << endl;    
        }

        // 访问完后解锁
        pthread_mutex_unlock(ptd->_pmtx);
    }


    // 记得释放传来的对象，不然内存泄漏了
    delete ptd;
    ptd = nullptr;

    return nullptr;
}

int main()
{
    // 局部条件变量
    pthread_cond_t cond;
    pthread_cond_init(&cond, nullptr);

    // 局部锁
    pthread_mutex_t mtx;
    pthread_mutex_init(&mtx, nullptr);

    // 各个函数执行的方法
    vector<pfunc> funcs = 
    { Thread_1_Func
    , Thread_2_Func
    , Thread_3_Func
    , Thread_4_Func
    };

    // 多个线程
    pthread_t tids[THREAD_NUM];

    // 创建THREAD_NUM个线程
    for(int i = 0; i < THREAD_NUM; ++i)
    {
        ThreadData* tmp = new ThreadData(to_string(i + 1) + "号线程", &mtx, &cond, funcs[i]);
        pthread_create(tids + i, nullptr, ThreadRoutine, (void*)tmp);
    }

    cout << "prepare to do the jobs" << endl;

    sleep(1);
    cout << "start doing jobs" << endl;

    // 发signal，让等待队列中的线程执行其方法
    int count = 0;
    while(count != 4)
    {
        //pthread_cond_signal(&cond);
        pthread_cond_broadcast(&cond);
        ++count;
        sleep(1);
    }

    quit = true;
    // quit改为true时，其他线程已经在等待队列中了，
    //得让各个线程都执行其一次方法才会循环上去判断quit改变了
    pthread_cond_broadcast(&cond);

    cout << "jobs done" << endl;

    for(int i = 0; i < THREAD_NUM; ++i)
    {
        pthread_join(tids[i], nullptr);
    }

    return 0;
}